package common

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strconv"
	"strings"
)

const (
	Semicolon = ";"
	Colon     = ":"
)

var (
	SupportContentType = []string{"html", "text"}
)

var (
	NotifySuccessful = &RetVal{Code: 0, error: nil, Desc: "Notify information successful."}
	NotifyFailed     = &RetVal{Code: 1, error: errors.New("Notify information faild, please try again.")}

	AppnameNotFound      = &RetVal{Code: 40, error: errors.New("Appname not found")}
	WarnDataPostFailed   = &RetVal{Code: 41, Desc: "Post Request Failed."}
	NotifyTypeNotSupport = &RetVal{Code: 41, error: errors.New("Notify type not support , only support email and sm.")}
	NotifyToNotSetting   = &RetVal{Code: 42, error: errors.New("Notify target not setting , examples email address or phone number.")}

	WarnRespUnmarshalFailed = &RetVal{Code: 51, error: errors.New("Resp Data Unmarshal Failed.")}
	RetValMarshalFailed     = &RetVal{Code: 52, error: errors.New("RetVal Marshal Failed in server internal.")}
)

type RetVal struct {
	error
	Code int
	Desc string
}

func (this *RetVal) ToJSON() string {
	if this.error != nil {
		this.Desc = this.error.Error()
	}
	var b []byte
	var err error
	if b, err = json.Marshal(this); err != nil {
		panic(RetValMarshalFailed.String())
	} else {
		return string(b)
	}
}

func (this *RetVal) String() string {
	if this.error != nil {
		this.Desc = this.error.Error()
	}
	return fmt.Sprintf("RetVal[Code=%d, Desc=%s]", this.Code, this.Desc)
}

func (this *RetVal) HasError() bool {
	return this.error != nil
}

type Dest struct {
	Phone string
	Email string
}

func (this *Dest) String() string {
	return this.Phone + Colon + this.Email
}

func (this *Dest) Conver(val string) {
	if val != "" {
		rs := strings.Split(val, Colon)
		length := len(rs)
		if length == 2 {
			this.Phone = rs[0]
			this.Email = rs[1]
		}
	}
}

type WarnData struct {
	Appname string
	Subject string
	Content string
	To      []Dest //To []Dest <-> "phone:email;phone:email[phone:email;....]"
	Html    bool
}

func WarnDataConverToValues(wd WarnData) url.Values {
	var toArray = make([]string, len(wd.To))
	for _, v := range wd.To {
		toArray = append(toArray, v.String())
	}
	to := strings.Join(toArray, Semicolon)
	return url.Values{
		"appname": {wd.Appname},
		"subject": {wd.Subject},
		"content": {wd.Content},
		"to":      {to},
		"html":    {strconv.FormatBool(wd.Html)},
	}
}

func (this *WarnData) SetHtml(val string) {
	if b, err := strconv.ParseBool(val); err == nil {
		this.Html = b
	} else {
		this.Html = false
	}
}

func (this *WarnData) CheckWarnData() *RetVal {
	if len(this.To) == 0 {
		return NotifyToNotSetting
	}
	return &RetVal{error: nil}
}

func ValuesConverToWarnData(values url.Values) *WarnData {
	var warnData = &WarnData{
		Appname: values.Get("appname"),
		Subject: values.Get("subject"),
		Content: values.Get("content"),
	}
	warnData.SetHtml(values.Get("html"))

	var toStr = values.Get("to")
	var destStrArray = strings.Split(toStr, Semicolon)
	var to = make([]Dest, len(destStrArray))
	for _, v := range destStrArray {
		var dest Dest
		dest.Conver(v)
		to = append(to, dest)
	}
	warnData.To = to
	return warnData
}
